#include "tcp_session.hpp"
#include "../core/connection_manager.hpp"
#include <iostream>
#include "../core/message_receiver.hpp"

/**
 * @brief 构造函数实现
 * @param socket 已建立的TCP套接字
 */
TcpSession::TcpSession(tcp::socket socket, IMessageReceiver& message_receiver)
    : socket_(std::move(socket)),
      message_receiver_(message_receiver) {
}

/**
 * @brief 启动会话
 * 开始异步读取数据
 */
void TcpSession::start() {
    do_read();
}

/**
 * @brief 停止会话
 * 关闭套接字连接
 */
void TcpSession::stop() {
    handle_disconnect();
    socket_.close();
}

/**
 * @brief 发送消息
 * @param data 要发送的数据
 * 
 * 将数据加入发送队列，如果当前没有正在进行的写操作，则开始写入
 */
void TcpSession::send(const std::vector<uint8_t>& data) {
    bool write_in_progress = !write_queue_.empty();
    write_queue_.push(data);
    if (!write_in_progress) {
        do_write();
    }
}

/**
 * @brief 异步读取数据
 * 从套接字读取二进制数据，处理粘包和分包问题
 * 
 * 使用固定长度的包头(4字节)来标识数据包长度
 * 协议格式: [包长度(4字节)][实际数据]
 * 包长度不包含包头本身的4字节
 */
void TcpSession::do_read() {
    auto self(shared_from_this());
    
    // 设置读取超时
    // socket_.set_option(boost::asio::socket_base::receive_timeout(
    //     boost::posix_time::seconds(30)));  // 30秒超时

    // 先读取4字节的包头
    boost::asio::async_read(socket_, read_buffer_,
        boost::asio::transfer_exactly(4),  // 确保读取4字节的包头
        [this, self](boost::system::error_code ec, std::size_t length) {
            if (!ec) {
                if (length != 4) {
                    std::cerr << "包头长度错误，期望4字节，实际" << length << "字节" << std::endl;
                    handle_disconnect();
                    return;
                }

                // 解析包头获取数据包长度
                const char* header = boost::asio::buffer_cast<const char*>(read_buffer_.data());
                uint32_t packet_length = ntohl(*reinterpret_cast<const uint32_t*>(header));  // 转换为主机字节序
                
                // 检查包长度是否合理
                if (packet_length > 1024 * 1024) {  // 限制最大1MB
                    std::cerr << "数据包长度过大: " << packet_length << "字节" << std::endl;
                    handle_disconnect();
                    return;
                }

                read_buffer_.consume(4);  // 清除包头

                // 读取实际数据
                boost::asio::async_read(socket_, read_buffer_,
                    boost::asio::transfer_exactly(packet_length),
                    [this, self, packet_length](boost::system::error_code ec, std::size_t length) {
                        if (!ec) {
                            if (length != packet_length) {
                                std::cerr << "数据长度错误，期望" << packet_length 
                                         << "字节，实际" << length << "字节" << std::endl;
                                handle_disconnect();
                                return;
                            }

                            // 获取完整的数据包
                            const char* data = boost::asio::buffer_cast<const char*>(read_buffer_.data());
                            std::vector<uint8_t> binary_data(data, data + packet_length);
                            read_buffer_.consume(packet_length);

                            // 这里可以添加数据处理逻辑
                            // 例如：解析协议、处理消息等
                            // 此处需要将消息打包给到对应接收队列，对应的队列是根据sessionid取模对应的队列数组下标，每个队列有自己对应的线程出来
                            message_receiver_.handle_message(binary_data, session_id_);

                            // 继续读取下一个数据包
                            do_read();
                        } else {
                            if (ec == boost::asio::error::operation_aborted) {
                                // 操作被取消，通常是正常关闭
                                return;
                            }
                            if (ec == boost::asio::error::timed_out) {
                                std::cerr << "读取数据超时" << std::endl;
                            } else if (ec != boost::asio::error::eof) {
                                std::cerr << "读取数据错误: " << ec.message() << std::endl;
                            }
                            handle_disconnect();
                        }
                    });
            } else {
                if (ec == boost::asio::error::operation_aborted) {
                    // 操作被取消，通常是正常关闭
                    return;
                }
                if (ec == boost::asio::error::timed_out) {
                    std::cerr << "读取包头超时" << std::endl;
                } else if (ec != boost::asio::error::eof) {
                    std::cerr << "读取包头错误: " << ec.message() << std::endl;
                }
                handle_disconnect();
            }
        });
}

/**
 * @brief 异步写入数据
 * 将消息队列中的数据写入套接字
 */
void TcpSession::do_write() {
    auto self(shared_from_this());

    // 准备发送的数据包
    const auto& data = write_queue_.front();
    std::vector<uint8_t> packet;
    
    // 添加包头（4字节长度）
    uint32_t length = static_cast<uint32_t>(data.size());
    packet.resize(4 + data.size());
    *reinterpret_cast<uint32_t*>(&packet[0]) = htonl(length);  // 转换为网络字节序
    std::copy(data.begin(), data.end(), packet.begin() + 4);

    // 异步写入数据
    boost::asio::async_write(socket_, boost::asio::buffer(packet),
        [this, self](boost::system::error_code ec, std::size_t /*length*/) {
            if (!ec) {
                write_queue_.pop();
                if (!write_queue_.empty()) {
                    do_write();
                }
            } else {
                handle_disconnect();
            }
        });
}

void TcpSession::handle_disconnect() {
    if (socket_.is_open()) {
        socket_.close();
        // 从连接管理器中移除会话
        ConnectionManager::get_instance().remove_connection(session_id_);
    }
}